// Code Generation for Clang level 4 compiler/interpreter
// AST version for stack machine (OOP)
// Includes procedures, functions, parameters, arrays, concurrency.
// Display machine.
// P.D. Terry, Rhodes University, 1996

#ifndef CGEN_H
#define CGEN_H

#include "misc.h"
#include "stkmc.h"
#include "report.h"

#define CGEN_headersize  STKMC_headersize
#define CGEN_levmax      STKMC_levmax

enum CGEN_operators {
  CGEN_opadd, CGEN_opsub, CGEN_opmul, CGEN_opdvd, CGEN_opeql, CGEN_opneq,
  CGEN_oplss, CGEN_opgeq, CGEN_opgtr, CGEN_opleq
};

struct NODE;
typedef NODE *AST;
typedef short CGEN_labels;

class CGEN {
  public:
    CGEN_labels undefined;    // for forward references

    CGEN(REPORT *R);
    // Initializes code generator

    AST emptyast(void);
    // Returns an empty (undefined) AST

    bool isrefast(AST a);
    // Returns true if a corresponds to a reference AST

    void negateinteger(AST &i);
    // Generates code to negate integer i

    void binaryintegerop(CGEN_operators op, AST &l, AST &r);
    // Generates code to perform infix operation op on l, r

    void comparison(CGEN_operators op, AST &l, AST &r);
    // Generates code to perform comparison operation op on l, r

    void readvalue(AST i);
    // Generates code to read value for i

    void writevalue(AST i);
    // Generates code to output value i

    void newline(void);
    // Generates code to output line mark

    void writestring(CGEN_labels location);
    // Generates code to output string stored at known location

    void stackstring(char *str, CGEN_labels &location);
    // Stores str in literal pool in memory and return its location

    void stackconstant(AST &c, int number);
    // Creates constant AST for constant c from number

    void stackaddress(AST &v, int level, int offset, bool byref);
    // Creates address AST for variable v with known level, offset

    void dereference(AST &a);
    // Generates code to replace address a by the value stored there

    void stackreference(AST &base, bool byref,
                        int level, int offset, AST &size);
    // Creates an actual parameter node for a reference parameter corresponding
    // to an array with given base and size

    void subscript(AST &base, bool byref,
                   int level, int offset, AST &size, AST &index);
    // Prepares to apply an index to an array with given base, with checks
    // that the limit on the bounds is not exceeded

    void assign(AST dest, AST expr);
    // Generates code to store value of expr on dest

    void openstackframe(int size);
    // Generates code to reserve space for size variables

    void leaveprogram(void);
    // Generates code needed to leave a program (halt)

    void leaveprocedure(int blocklevel);
    // Generates code needed to leave a regular procedure at a given blocklevel

    void leavefunction(int blocklevel);
    // Generates code needed to leave a function at given blocklevel

    void functioncheck(void);
    // Generates code to ensure that a function has returned a value

    void storelabel(CGEN_labels &location);
    // Stores address of next instruction in location for use in backpatching

    void jump(CGEN_labels &here, CGEN_labels destination);
    // Generates unconditional branch from here to destination

    void jumponfalse(AST condition, CGEN_labels &here, CGEN_labels destination);
    // Generates branch from here to destination, dependent on condition

    void backpatch(CGEN_labels location);
    // Stores the current location counter as the address field of the branch
    // instruction currently held in an incomplete form at location

    void markstack(AST &p, int level, int entrypoint);
    // Generates code to reserve mark stack storage before calling procedure p
    // with known level and entrypoint

    void linkparameter(AST &p, AST &par);
    // Adds par to the actual parameter list for call to procedure p

    void call(AST &p);
    // Generates code to enter procedure p

    void cobegin(CGEN_labels &location);
    // Generates code to initiate concurrent processing

    void coend(CGEN_labels location, int number);
    // Generates code to terminate concurrent processing

    void forkprocess(AST &p);
    // Generates code to initiate process p

    void signalop(AST s);
    // Generates code for semaphore signalling operation on s

    void waitop(AST s);
    // Generates code for semaphore wait operation on s

    void dump(void);
    // Generates code to dump the current state of the evaluation stack

    void getsize(int &codelength, int &initsp);
    // Returns length of generated code and initial stack pointer

    int gettop(void);
    // Returns codetop

    void emit(int word);
    // Emits single word

  private:
    REPORT *Report;
    bool generatingcode;
    STKMC_address codetop, stktop;
    void binaryop(CGEN_operators op, AST &left, AST &right);
};

#endif /*CGEN_H*/
